#include "task_lwip_comm.h"

#include "FreeRTOS.h"
#include "task.h"

#include "OutputLog.h"
#include "device_resource.h"
#include "eth_hard_interface.h"
#include "ethernetif.h"
#include "lwip/apps/netbiosns.h"
#include "lwip/dhcp.h"
#include "lwip/sockets.h"
#include "lwip/tcpip.h"
#include "print_rtt.h"
#include "telnet_cli_port.h"
static StackType_t xLwipCommStack[1024]; // 静态栈
static StaticTask_t xLwipCommTCB;        // 静态 TCB（可选，省堆）
struct netif gnetif;
ip4_addr_t ipaddr;
ip4_addr_t netmask;
ip4_addr_t gw;

/*  Creates a new DHCP client for this interface on the first call.
Note: you must call dhcp_fine_tmr() and dhcp_coarse_tmr() at
the predefined regular intervals after starting the client.
You can peek in the netif->dhcp struct for the actual DHCP status.*/
typedef enum
{
  TEST_STATUS_DPT_TO_CONNECT = 0,
  TEST_STATUS_DPT_SEND,
  TEST_STATUS_DPT_WAIT_RECV,
  TEST_STATUS_DPT_ERROR,

} TEST_STATUS_DPT;

static void vLwipCommTaskEntry(void *pvParameters)
{
  int ret;
  int times=0;

  struct sockaddr_in addr = {0};
  int listen_fd, client_fd;
  vRegisterCLICommands();
  (void)pvParameters;
  lwip_net_status = LWIP_PROCESS_INIT;
  tcpip_init(NULL, NULL);

  IP4_ADDR(&ipaddr,
           setting_para->port2_IPV4[0],
           setting_para->port2_IPV4[1],
           setting_para->port2_IPV4[2],
           setting_para->port2_IPV4[3]);
  IP4_ADDR(&netmask,
           setting_para->port2_IPV4_netmask[0],
           setting_para->port2_IPV4_netmask[1],
           setting_para->port2_IPV4_netmask[2],
           setting_para->port2_IPV4_netmask[3]);
  IP4_ADDR(&gw,
           setting_para->port2_IPV4_GW[0],
           setting_para->port2_IPV4_GW[1],
           setting_para->port2_IPV4_GW[2],
           setting_para->port2_IPV4_GW[3]);
  gnetif.hwaddr_len = ETHARP_HWADDR_LEN;
  memcpy(gnetif.hwaddr, net_config->eth1_mac, 6);
  netif_add(&gnetif, &ipaddr, &netmask, &gw, NULL, &ethernetif_init, &tcpip_input);
  /* add the network interface (IPv4/IPv6) without RTOS */
  gnetif.hostname = "DGU_eth1";
  netbiosns_init();
  netbiosns_set_name("DGU_eth1");
  /* Registers the default network interface */
  netif_set_default(&gnetif);
  netif_set_up(&gnetif);
	LOG_INFO("IP: %s\r\n", ip4addr_ntoa(&gnetif.ip_addr));
	LOG_INFO("MASK: %s\r\n", ip4addr_ntoa(&gnetif.netmask));
	LOG_INFO("GW: %s\r\n", ip4addr_ntoa(&gnetif.gw));
	LOG_INFO("LWIP MAC %02x:%02x:%02x:%02x:%02x:%02x\r\n",
       gnetif.hwaddr[0], gnetif.hwaddr[1], gnetif.hwaddr[2],
       gnetif.hwaddr[3], gnetif.hwaddr[4], gnetif.hwaddr[5]);
  for (;;)
  {
    switch (lwip_net_status)
    {
    case LWIP_PROCESS_INIT:
      if (setting_para->port2_DHCPV4_FLAG == 1)
      {
        ip_addr_set_zero_ip4(&ipaddr);
        ip_addr_set_zero_ip4(&netmask);
        ip_addr_set_zero_ip4(&gw);
        netif_set_addr(&gnetif, &ipaddr, &netmask, &gw);
        /* 2. 停掉旧 DHCP（如果曾经跑过） */
        dhcp_stop(&gnetif);
        /* 3. 启动 DHCP 客户端 */
        ret=dhcp_start(&gnetif);
        if (ret != ERR_OK)
        {
          LOG_ERROR("lwip dhcp start fail...\n\n");
          lwip_net_status = LWIP_DHCP_FAILED;
        }
        times = 0;
        LOG_COLOR(YELLOW,"eth1 DHCP ...\r\n");
        lwip_net_status = LWIP_DHCP_PROCESS;
      }
      else
      {
        memcpy(&net_config->eth1_ipv4, &ipaddr, sizeof(ipaddr));
        memcpy(&net_config->eth1_ipv4_netmask, &netmask, sizeof(netmask));
        memcpy(&net_config->eth1_ipv4_gw, &gw, sizeof(gw));
        net_config->eth1_dhcp_flag = 0;
        lwip_net_status = LWIP_READY_RUNNING;
      }
      /* code */
      break;
    case LWIP_DHCP_PROCESS:
		{
      if (dhcp_supplied_address(&gnetif))
      {
        LOG_COLOR(YELLOW,"eth1 DHCP OK  ip=%s\r\n", ip4addr_ntoa(&gnetif.ip_addr));
        net_config->eth1_ipv4[0] = ip4_addr1(&gnetif.ip_addr);
        net_config->eth1_ipv4[1] = ip4_addr2(&gnetif.ip_addr);
        net_config->eth1_ipv4[2] = ip4_addr3(&gnetif.ip_addr);
        net_config->eth1_ipv4[3] = ip4_addr4(&gnetif.ip_addr);

        net_config->eth1_ipv4_netmask[0] = ip4_addr1(&gnetif.netmask);
        net_config->eth1_ipv4_netmask[1] = ip4_addr2(&gnetif.netmask);
        net_config->eth1_ipv4_netmask[2] = ip4_addr3(&gnetif.netmask);
        net_config->eth1_ipv4_netmask[3] = ip4_addr4(&gnetif.netmask);

        net_config->eth1_ipv4_gw[0] = ip4_addr1(&gnetif.gw);
        net_config->eth1_ipv4_gw[1] = ip4_addr2(&gnetif.gw);
        net_config->eth1_ipv4_gw[2] = ip4_addr3(&gnetif.gw);
        net_config->eth1_ipv4_gw[3] = ip4_addr4(&gnetif.gw);
        net_config->eth1_dhcp_flag = 1;
        lwip_net_status = LWIP_READY_RUNNING;
				break;
      }
      if (++times > 8)
      { /* 8 次重试后放弃 */
				LOG_COLOR(YELLOW,"DHCP FAIL, back to static\r\n");
        dhcp_stop(&gnetif);
        // netif_set_addr(&gnetif, &ip, &mask, &gw); /* 回退静态 */
        lwip_net_status = LWIP_DHCP_FAILED;
				break;
      }
      break;
		}
    case LWIP_DHCP_FAILED:
		{
      IP4_ADDR(&ipaddr,
               setting_para->port2_IPV4[0],
               setting_para->port2_IPV4[1],
               setting_para->port2_IPV4[2],
               setting_para->port2_IPV4[3]);
      IP4_ADDR(&netmask,
               setting_para->port2_IPV4_netmask[0],
               setting_para->port2_IPV4_netmask[1],
               setting_para->port2_IPV4_netmask[2],
               setting_para->port2_IPV4_netmask[3]);
      IP4_ADDR(&gw,
               setting_para->port2_IPV4_GW[0],
               setting_para->port2_IPV4_GW[1],
               setting_para->port2_IPV4_GW[2],
               setting_para->port2_IPV4_GW[3]);
      net_config->eth1_dhcp_flag = -1;
      netif_set_addr(&gnetif, &ipaddr, &netmask, &gw);
      lwip_net_status = LWIP_READY_RUNNING;
      break;
		}
    case LWIP_READY_RUNNING:
    {
      while (1)
      {
        addr.sin_family = AF_INET;
        addr.sin_port = htons(23); /* telnet 标准口 */
        addr.sin_addr.s_addr = INADDR_ANY;

        listen_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
        if (listen_fd < 0)
        {
          LOG_ERROR("create Telnet Socket failed,errno: %d", errno);
					vTaskDelay(pdMS_TO_TICKS(1000));
          continue;
        }
        ret = bind(listen_fd, (struct sockaddr *)&addr, sizeof(addr));
        if (ret < 0)
        {
					vTaskDelay(pdMS_TO_TICKS(1000));
          continue;
        }
        ret = listen(listen_fd, 2);
        if (ret < 0)
        {
					vTaskDelay(pdMS_TO_TICKS(1000));
          continue;
        }
        for (;;)
        {
          client_fd = accept(listen_fd, NULL, NULL); /* 阻塞直到有客户 */
          if (client_fd >= 0)
          {
            telnet_session_task(client_fd);
          }
					else
					{
						close(listen_fd);
						break;
					}
          vTaskDelay(pdMS_TO_TICKS(1000));
        }
        
      }
    }
    default:
      break;
    }
    vTaskDelay(1000);
  }
}

void vLwipCommTaskCreate(void)
{
  TaskHandle_t xHandle = NULL;
  taskENTER_CRITICAL(); // 进入临界区
                        // system_led_init();

  /* 创建system_led任务 - 静态方法 */
  xHandle = xTaskCreateStatic(
      (TaskFunction_t)vLwipCommTaskEntry,                     /* 任务入口函数 */
      (const char *)"lwip_comm",                              /* 任务名字 */
      (uint16_t)sizeof(xLwipCommStack) / sizeof(StackType_t), /* 任务栈大小 */
      (void *)NULL,                                           /* 任务入口函数参数 */
      (UBaseType_t)6,                                         /* 任务的优先级 */
      (StackType_t *)xLwipCommStack,                          /* 静态栈数组 */
      (StaticTask_t *)&xLwipCommTCB);                         /* 静态TCB的地址 */

  if (xHandle != NULL)
  {
    LOG_INFO("Create Indicator test Task success...\r\n");
  }
  taskEXIT_CRITICAL(); // 退出临界区，无论成功失败都要退出
}
